package C059;


import java.io.*;
import java.util.Arrays;

/**
 * ClassName: c04
 * Package: C059
 * Description: https://www.luogu.com.cn/problem/U107394 字典序最小的拓扑排序
 *
 *
 * 1、构建链式前向星的图 以及 更新入度表
 * 2、自己实现小跟堆(比工具类快)，只加入入度为0的点(堆的形式替换传统的队列弹出的形式)
 * 3.0 弹出小跟堆顶元素，更新入度表
 * 3.1 每个节点入度判断，为0入小跟堆
 * 3.2 ans 加入该元素，堆不为空，3.0
 *
 * ans 就是最小的字典拓扑序
 *
 * @Author BCXJ
 * @Create 2025/10/17 08:36
 * @Version 1.0
 * @Since 1.0
 */
public class c04 {
    /*
5 4
1 2
2 4
3 4
5 4

5 4
1 2
2 4
3 4
5 4
     */

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StreamTokenizer in = new StreamTokenizer(br);
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        while (in.nextToken() != StreamTokenizer.TT_EOF) {
            n = (int) in.nval;
            in.nextToken();
            m = (int) in.nval;
            build(n);
            for (int i = 0, from, to; i < m; i++) {
                in.nextToken();
                from = (int) in.nval;
                in.nextToken();
                to = (int) in.nval;
                addEdge(from, to);
            }
            topoSort();
            for (int i = 0; i < n - 1; i++) {
                out.print(ans[i] + " ");
//                System.out.print(ans[i] + " ");
            }
            out.println(ans[n - 1]);
//            System.out.println(ans[n - 1]);
        }
        out.flush();
        out.close();
        br.close();
    }

    // 拓扑排序
    private static void topoSort() {
        // 统计入度为0的点入堆
        for (int i = 1; i <= n; i++) {
            if(0 == indegree[i]) {
                push(i);
            }
        }
        // 堆是否为空
        int index = 0;
        while(! isEmpty()) {
            // 弹出第一个元素, 入度为0的点入小跟堆
            int node = pop();
            ans[index++] = node;
            // 边的遍历
            for (int curEdge = head[node]; curEdge != 0 ; curEdge = next[curEdge]) {
                if(-- indegree[tos[curEdge]] == 0) {
                    push(tos[curEdge]);
                }
            }
        }


    }


    static int MAXN = 100001;
    static int MAXM = 100001;
    // n 点数， m 边数
    static int n,m;

    // 入度表
    static int[] indegree = new int[MAXN];

    // 链式前向星
    static int[] head = new int[MAXN];
    static int[] next = new int[MAXM];
    static int[] tos = new int[MAXM];
    static int cnt = 1; // 边编号

    //ans
    static int[] ans = new int[MAXN];

    // 堆
    static int[] heap = new int[MAXN];
    static int heapSize = 0;

    /**
     * 初始化链式前向星图
     * @param n
     */
    public static void build(int n) {
        // 初始化
        cnt = 1;
        heapSize = 0;
        // 入度初始化
        Arrays.fill(indegree, 0, n + 1, 0);
        // 堆初始化
        Arrays.fill(head, 0, n + 1, 0);
    }

    /**
     * 加边
     * @param from
     * @param to
     */
    public static void addEdge(int from, int to) {
        next[cnt] = head[from];
        head[from] = cnt;
        tos[cnt ++] = to;
        indegree[to] ++;
    }


    // push 小跟堆加入元素
    public static void push(int node) {
        int index = heapSize ++;
        heap[index] = node;
        //heapInsert的过程
        while (heap[index] < heap[(index - 1) / 2]) {
            swap(heap, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    private static void swap(int[] heap, int i, int j) {
        if(i == j) {
            return;
        }
        heap[i] = heap[i] ^ heap[j];
        heap[j] = heap[i] ^ heap[j];
        heap[i] = heap[i] ^ heap[j];
    }

    // pop弹出元素
    public static int pop() {
        int ans = heap[0];
        heap[0] = heap[--heapSize];
        // heapify的过程
        int i = 0;
        int l = 1; // 左边的子节点
        while(l < heapSize) {
            int best = l + 1 < heapSize && heap[l] > heap[l + 1] ? l + 1 : l;
            best = heap[best] < heap[i] ? best : i;
            if(best == i) {
                break;
            }
            swap(heap, best, i);
            i = best;
            l = i * 2 + 1;
        }
        return ans;
    }

    // 堆是否为空
    public static boolean isEmpty() {
        return heapSize == 0;
    }
}
